package com.framework.workflow.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.framework.common.config.SessionUtil;
import com.framework.workflow.dto.NodeUser;
import com.framework.workflow.mapper.WfLogMapper;
import com.framework.workflow.model.WfLog;
import com.framework.workflow.model.WfProcessInstance;
import com.framework.workflow.service.IWfLogService;
import com.framework.workflow.vo.ProcessDetail;
import com.framework.workflow.vo.WfLogVo;
import lombok.extern.log4j.Log4j2;
import org.apache.commons.lang3.StringUtils;
import org.flowable.engine.HistoryService;
import org.flowable.engine.RuntimeService;
import org.flowable.engine.TaskService;
import org.flowable.engine.task.Comment;
import org.flowable.task.api.Task;
import org.flowable.task.api.TaskInfo;
import org.flowable.task.api.history.HistoricTaskInstance;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.ObjectUtils;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * @author zzg
 */
@Service
@Log4j2
public class WfLogService implements IWfLogService {
    @Autowired
    private ProcessInstanceService processInstanceService;
    @Autowired
    private VariableService variableService;
    @Autowired
    private TaskService taskService;
    @Autowired
    private HistoryService historyService;
    @Autowired
    private WfLogMapper wfLogMapper;

    @Override
    public void save(Task task, String status) {
        WfLog log = new WfLog();
        log.setCreateTime(new Date());
        log.setProcDefKey(task.getProcessDefinitionId());
        log.setProcInsId(task.getProcessInstanceId());
        log.setTaskDefKey(task.getTaskDefinitionKey());
        log.setTaskId(task.getId());
        log.setAssignee(task.getAssignee());
        log.setNodeName(task.getName());
        log.setStatus(status);
        log.setDeptId(SessionUtil.getDefaultDeptId());

        wfLogMapper.insert(log);
    }

    @Override
    public List<WfLog> findByProcInsId(String processInstanceId) {
        LambdaQueryWrapper<WfLog> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(WfLog::getProcInsId, processInstanceId);
        queryWrapper.orderByDesc(WfLog::getCreateTime);
        return wfLogMapper.selectList(queryWrapper);
    }

    @Override
    public List<WfLogVo> listLog(String businessId) {
        List<WfLogVo> list = new ArrayList<>();
        WfProcessInstance instance = processInstanceService.findByBusinessId(businessId);
        if (null == instance) {
            log.error("流程数据被删除，找不到流程信息");
            return list;
        }
        List<WfLog> hisLogs = findByProcInsId(instance.getProcInstId());
        hisLogs.forEach(it -> {
            WfLogVo vo = new WfLogVo();
            BeanUtils.copyProperties(it, vo);
            NodeUser user = variableService.userNodeById(it.getAssignee());
            if (null != user) {
                vo.setUserName(user.getName());
            }
            NodeUser keyPair = variableService.deptNodeById(it.getDeptId());
            if (null != keyPair) {
                vo.setDeptName(keyPair.getName());
            }

            List<Comment> comments = taskService.getTaskComments(it.getTaskId());
            if (comments.size() >= 1) {
                String msg = comments.get(comments.size() - 1).getFullMessage();
                vo.setDesc(msg);
            }

            list.add(vo);
        });

        List<Task> tasks = taskService
                .createTaskQuery()
                .processInstanceId(instance.getProcInstId())
                .orderByTaskCreateTime()
                .asc()
                .list();

        for (TaskInfo taskInfo : tasks) {
            WfLogVo vo = new WfLogVo();
            vo.setId(taskInfo.getId());
            vo.setAssignee(taskInfo.getAssignee());
            NodeUser user = variableService.userNodeById(taskInfo.getAssignee());
            if (null != user) {
                vo.setUserName(user.getName());
            }
            vo.setDesc("待处理");
            vo.setNodeName(taskInfo.getName());
            list.add(vo);
        }

        return list;
    }

    @Override
    public List<ProcessDetail> processDiagram(String insId) {
        // 取流程历史记录
        List<WfLog> hisLogs = findByProcInsId(insId);
        List<Task> tasks = taskService
                .createTaskQuery()
                .processInstanceId(insId)
                .orderByTaskCreateTime()
                .asc()
                .list();

        if (hisLogs.size() == 0) {
            List<HistoricTaskInstance> hisTasks = historyService
                    .createHistoricTaskInstanceQuery()
                    .processInstanceId(insId)
                    .orderByTaskCreateTime()
                    .asc()
                    .finished()
                    .list();
            hisTasks.forEach(it -> {
                WfLog log = new WfLog();
                log.setId(it.getId());
                log.setAssignee(it.getAssignee());
                log.setNodeName(it.getName());
                log.setCreateTime(it.getCreateTime());
                log.setTaskDefKey(it.getTaskDefinitionKey());
                hisLogs.add(log);
            });
        }

        List<ProcessDetail> list = new ArrayList<>();
        // 生成历史列表, 历史列表不区分子流程， 直接列出
        setDetail(list, hisLogs, 1);

        // 加上当前处理人列表
        if (ObjectUtils.isEmpty(tasks.size())) {
            return list;
        }

        List<WfLog> logs = new ArrayList<>();
        Map<String, List<Task>> map = tasks.stream().collect(Collectors.groupingBy(Task::getTaskDefinitionKey));

        map.forEach((d, v) -> {
            Task it = v.get(0);
            String assignees = StringUtils.join(v.stream().map(Task::getAssignee).toArray(), ",");
            WfLog log = new WfLog();
            log.setAssignee(assignees);
            log.setId(it.getId());
            log.setNodeName(it.getName());
            log.setCreateTime(it.getCreateTime());
            log.setTaskDefKey(it.getTaskDefinitionKey());
            logs.add(log);
        });
        // 加入当前处理人
        setDetail(list, logs, 2);

        return list;
    }

    /**
     * 生成前端展示列表
     * @param allList 返回值
     * @param logs 所有列表
     * @param type 类型
     */
    private void setDetail(List<ProcessDetail> allList, List<WfLog> logs, Integer type) {
        for (WfLog curr : logs) {
            ProcessDetail  node = new ProcessDetail();
            node.setId(curr.getTaskDefKey());
            ProcessDetail.Detail detail = new ProcessDetail.Detail();
            String assignee = curr.getAssignee();
            if (StringUtils.isNotBlank(assignee)) {
                String[] assignees = assignee.split(",");
                List<String> list = new ArrayList<>();
                for (String it : assignees) {
                    NodeUser user = variableService.userNodeById(it);
                    if (null != user) {
                        list.add(user.getName());
                    } else {
                        list.add(it);
                    }
                }
                detail.setName(StringUtils.join(list.toArray(), ","));
            }

            List<Comment> comments = taskService.getTaskComments(curr.getTaskId());
            String nodeName = curr.getNodeName();
            if (comments.size() >= 1) {
                String msg = comments.get(comments.size() - 1).getFullMessage();
                detail.setDesc(msg);
                node.setDate(comments.get(comments.size() - 1).getTime());
            }
            // 设置节点名称
            node.setName(nodeName);
            node.add(detail);
            node.setType(type);
            allList.add(node);
        }
    }
}
